package fts.ftsmonitoring.impl;

import static java.nio.file.StandardWatchEventKind.ENTRY_CREATE;
import static java.nio.file.StandardWatchEventKind.ENTRY_DELETE;
import static java.nio.file.StandardWatchEventKind.ENTRY_MODIFY;

import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Path;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author Igor Zilberman (304033327)
 * 
 * JSRFileVisitor is used in conjunction with the walkFileTree of File class
 * Responsible of registering directory tree with watcher service
 */
public class JSRFileVisitor implements FileVisitor<Path> {

	WatchService watcherSvc;
	HashMap<WatchKey, Path> keyToPathMap = new HashMap<WatchKey, Path>();
	ArrayList<Path[]> pathChangeQueue = new ArrayList<Path[]>();
	
	JSRFileVisitor(WatchService watcherSvc)
	{
		this.watcherSvc = watcherSvc;
	}
	
	
	/* (non-Javadoc)
	 * @see java.nio.file.FileVisitor#postVisitDirectory(java.lang.Object, java.io.IOException)
	 */
	public FileVisitResult postVisitDirectory(Path arg0, IOException arg1) {
		// TODO Auto-generated method stub
		return FileVisitResult.CONTINUE;
	}

	/* (non-Javadoc)
	 * @see java.nio.file.FileVisitor#preVisitDirectory(java.lang.Object)
	 */
	public FileVisitResult preVisitDirectory(Path arg0) {
		// TODO Auto-generated method stub
			WatchKey key;
			try {
				key = arg0.register(watcherSvc, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
				if(keyToPathMap.containsKey(key))
				{
					pathChangeQueue.add(new Path[]{keyToPathMap.remove(key), arg0});
				}
				keyToPathMap.put(key, arg0);
				System.out.println("Added folder watch: " + arg0.toString());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		return FileVisitResult.CONTINUE;
	}

	public Path[] getPathChange()
	{
		if(pathChangeQueue.isEmpty())
		{
			return null;
		}
		else
		{
			return pathChangeQueue.remove(0);
		}
	}

	/* (non-Javadoc)
	 * @see java.nio.file.FileVisitor#preVisitDirectoryFailed(java.lang.Object, java.io.IOException)
	 */
	public FileVisitResult preVisitDirectoryFailed(Path arg0, IOException arg1) {
		// TODO Auto-generated method stub
		return FileVisitResult.CONTINUE;
	}

	/* (non-Javadoc)
	 * @see java.nio.file.FileVisitor#visitFile(java.lang.Object, java.nio.file.attribute.BasicFileAttributes)
	 */
	public FileVisitResult visitFile(Path arg0, BasicFileAttributes arg1) {
		// TODO Auto-generated method stub
		return FileVisitResult.CONTINUE;
	}

	/* (non-Javadoc)
	 * @see java.nio.file.FileVisitor#visitFileFailed(java.lang.Object, java.io.IOException)
	 */
	public FileVisitResult visitFileFailed(Path arg0, IOException arg1) {
		// TODO Auto-generated method stub
		return FileVisitResult.TERMINATE;
	}

	/**
	 * @param key WatchKey of a registered path
	 * @return Path matching the key
	 */
	Path getPath(WatchKey key)
	{
		if(keyToPathMap.containsKey(key))
		{
			return keyToPathMap.get(key);
		}
		return null;
	}
	
	
	/**
	 * Stops all registered watchers
	 */
	void stopWatchers()
	{
		for(WatchKey key:keyToPathMap.keySet())
		{
			key.cancel();
		}
		keyToPathMap.clear();
	}
}
